﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
using System.Text;

namespace chesslibrary.cs
{
    public class rules_chess
    {
        private game_chess g;
		public rules_chess(game_chess g)
		{
			this.g=g;
		}
        public move_pieces createMove(properties_cell source,properties_cell target) 
		{
	        ArrayList moves=getMoves(source);
	      return createMove(source,target,moves);
		}
        public move_pieces createMove(properties_cell source,properties_cell target,ArrayList moves) 
		{
			if (!moves.Contains(target))
	 		{
				throw new ChessException("Illegal move!");
			}
            if (isPawnBegin(source,target))
				return new properties_pawn(source,target,g.ActiveSide());
			if (isEnPassant(source,target))
			{
				EnPassant m=new EnPassant(source,target,g.ActiveSide());
				properties_cell enpassant=g[source.Row,target.Col];
				pieces_pawn p=(pieces_pawn)(enpassant.pieces_chess);
				m.SetEnPassantPiece(p);
                return m;
			}
            if (isPromotion(source,target))
			{
				grade m=new grade(source,target,g.ActiveSide());
				m.SetGradePiece(new pieces_queen(g.ActiveSide()));
			    return m;
			}
			return new functionmoves(source,target,g.ActiveSide());
		}
        private bool isPawnBegin(properties_cell source,properties_cell target)
		{
			pieces_chess p=source.pieces_chess;

			if (p is pieces_pawn)
			{
				pieces_pawn pawn=(pieces_pawn)p;

				if (!p.HasMoved())
				{
					if (Math.Abs(source.Row-target.Row)>1)
					{
						return true;
					}
				}
			}
			return false;
		}
        private bool isEnPassant(properties_cell source,properties_cell target)
		{
			pieces_chess sourcepiece=source.pieces_chess;
			pieces_chess targetpiece=target.pieces_chess;
            if (sourcepiece is pieces_pawn)
			{
				if (targetpiece==null && source.Col!=target.Col)
				{
					return true;
				}
			}
			return false;
		}
        private bool isPromotion(properties_cell source,properties_cell target)
		{
			pieces_chess sourcepiece=source.pieces_chess;
			pieces_chess targetpiece=target.pieces_chess;
            if (sourcepiece is pieces_pawn)
			{
				if ((g.ActiveSide()==color_pieces.White && target.Row==8) || (g.ActiveSide()==color_pieces.Black && target.Row==1))
				{
					return true;
				}
			}
			return false;
		}
        public bool isCheck(color_pieces side)
		{
			ArrayList enemymoves=new ArrayList();
			properties_table enemysquares=g[side.Enemy];
			IEnumerator i=enemysquares.GetEnumerator();
            while (i.MoveNext())
			{
				properties_cell s=(properties_cell)i.Current;
				enemymoves.AddRange(getPossibleMoves(s));
			}
            return (enemymoves.Contains(g.KingSquare(side)));
		}
		public int moveCount(color_pieces side)
		{
			ArrayList moves=new ArrayList();
			properties_table squares=g[side];
			IEnumerator i=squares.GetEnumerator();
            while (i.MoveNext())
			{
				properties_cell s=(properties_cell)i.Current;
				moves.AddRange(getMoves(s));
			}
            return (moves.Count);		
		}
		public bool isCheckmate(color_pieces side)
		{
		    return (isCheck(side) && moveCount(side)==0);
		}
		public bool isStalemate(color_pieces side)
		{
			return (!isCheck(side) && moveCount(side)==0);
		}
        public ArrayList getMoves(properties_cell s)
		{			
			ArrayList moves=getPossibleMoves(s);
            ArrayList tobeRemoved=new ArrayList();
			IEnumerator i=moves.GetEnumerator();
			while (i.MoveNext())
			{
				properties_cell dest=(properties_cell)i.Current;
				if (causesCheck(s,dest,moves))
				{
					tobeRemoved.Add(dest);
				}
			}
		    i=tobeRemoved.GetEnumerator();
            while (i.MoveNext())
			{
				moves.Remove(i.Current);
			}
			return moves;
		}
        private ArrayList getPossibleMoves(properties_cell s)
		{
			ArrayList moves=null;
            if (s.IsEmpty())
				return new ArrayList();
            if (s.pieces_chess is pieces_pawn)
				return getMovesForPawn(s);
		    if (s.pieces_chess is pieces_rook)
				return getMovesForRook(s);
            if (s.pieces_chess is pieces_bishop)
				return getMovesForBishop(s);
            if (s.pieces_chess is pieces_knight)
				return getMovesForKnight(s);
            if (s.pieces_chess is pieces_king)
            { 
                if(chessgame(s)!=getMovesForRook(s))
                {
			 	return getMovesForKing(s);
                }
            }
            if (s.pieces_chess is pieces_queen)
				return getMovesForQueen(s);
			return moves;
		}
		private bool causesCheck(properties_cell source,properties_cell dest,ArrayList moves)
		{
				move_pieces m=createMove(source,dest,moves);
				g.ExecuteMove(m);
            	if (isCheck(m.Owner))
				{
					g.UndoMove();
					return true;
				}
				g.UndoMove();
			return false;
		}
        private ArrayList getMovesForKing(properties_cell s)
		{
			ArrayList moves=new ArrayList();
			color_pieces Owner=s.pieces_chess.Owner;
            properties_cell test;
            test = g.north(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.northeast(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.east(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.southeast(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.south(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.southwest(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.west(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            test = g.northwest(s);
            if (test != null && !test.IsOwnedBy(Owner))
                moves.Add(test);
            return moves;
		}
        private ArrayList getMovesForRook(properties_cell s)
		{
			ArrayList moves=new ArrayList();
			color_pieces Owner=s.pieces_chess.Owner;
			properties_cell test;
            test=s;
			while ((test=g.east(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.west(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.north(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.south(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            return moves;
		}
        private ArrayList getMovesForBishop(properties_cell s)
		{
			ArrayList moves=new ArrayList();
			color_pieces Owner=s.pieces_chess.Owner;
			properties_cell test;
            test=s;
			while ((test=g.northeast(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.southeast(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.northwest(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            test=s;
			while ((test=g.southwest(test))!=null)
			{
				if (test.IsEmpty())
				{
					moves.Add(test);
				}
                if (test.IsEnemyOf(Owner))
				{
					moves.Add(test);
					break;
				}
                if (test.IsOwnedBy(Owner))
				{
					break;
				}
			}
            return moves;
		}
        public ArrayList getMovesForQueen(properties_cell s)
		{
			ArrayList moves=getMovesForRook(s);
            moves.AddRange(getMovesForBishop(s));
            return moves;
		}
        public ArrayList chessgame(properties_cell s)
        {
            ArrayList moves = getMovesForRook(s);
           if(getMovesForKing(s)==null);
            return moves;
        }
        public ArrayList getMovesForKnight(properties_cell s)
		{
			ArrayList moves=new ArrayList();
			color_pieces Owner=s.pieces_chess.Owner;
			properties_cell test;
			properties_cell test2;
			properties_cell test3;
			test=g.east(s);
			if (test!=null)
			{
				test2=g.north(test);
				if (test2!=null)
				{
					test3=g.north(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	    			test3=g.east(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      	}
                test2=g.south(test);
				if (test2!=null)
				{
					test3=g.south(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      	test3=g.east(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      	}
		}
            test=g.west(s);
			if (test!=null)
			{
				test2=g.north(test);
				if (test2!=null)
				{
					test3=g.north(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      		test3=g.west(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      	}
                test2=g.south(test);
				if (test2!=null)
				{
					test3=g.south(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      
				test3=g.west(test2);
					if (test3!=null && (!test3.IsOwnedBy(Owner)))
					{
						moves.Add(test3);
					}
	      	}
		}
            return moves;
		}
        public ArrayList getMovesForPawn(properties_cell s)
		{
			ArrayList moves=new ArrayList();
			color_pieces Owner=s.pieces_chess.Owner;
			properties_cell test;
            if (Owner.IsWhite())
			{
				test=g.north(s);
				if (test!=null && test.IsEmpty())
				{
					moves.Add(test);
					if (!s.pieces_chess.HasMoved())
					{
						test=g.north(test);
						if (test!=null && test.IsEmpty())
						{
							moves.Add(test);
						}
					}
				}
				test=g.northwest(s);
				if (test!=null && test.IsEnemyOf(Owner))
				{
					moves.Add(test);
				}
				test=g.northeast(s);
				if (test!=null && test.IsEnemyOf(Owner))
				{
					moves.Add(test);
				}
                if (s.Row==5)
				{
					properties_cell pawnsquare=g.east(s);
                    if (pawnsquare!=null && pawnsquare.IsEnemyOf(Owner) && pawnsquare.pieces_chess is pieces_pawn)
					{
						pieces_pawn enemypawn=(pieces_pawn)pawnsquare.pieces_chess;
						if (g.EnPassantPiece==enemypawn)
						{
							moves.Add(g.northeast(s));
						}
					}
                    pawnsquare=g.west(s);
                    if (pawnsquare!=null && pawnsquare.IsEnemyOf(Owner) && pawnsquare.pieces_chess is pieces_pawn)
					{
						pieces_pawn enemypawn=(pieces_pawn)pawnsquare.pieces_chess;
						if (g.EnPassantPiece==enemypawn)
						{
							moves.Add(g.northwest(s));
						}
					}
				}
			}
			else
			{
				test=g.south(s);
				if (test!=null && test.IsEmpty())
				{
					moves.Add(test);
					if (!s.pieces_chess.HasMoved())
					{
					test=g.south(test);
						if (test!=null && test.IsEmpty())
						{
							moves.Add(test);
						}
					}
				}
				test=g.southwest(s);
				if (test!=null && test.IsEnemyOf(Owner))
				{
					moves.Add(test);
				}
                test=g.southeast(s);
				if (test!=null && test.IsEnemyOf(Owner))
				{
					moves.Add(test);
				}
                if (s.Row==4)
				{
					properties_cell pawnsquare=g.east(s);
                    if (pawnsquare!=null && pawnsquare.IsEnemyOf(Owner) && pawnsquare.pieces_chess is pieces_pawn)
					{
						pieces_pawn enemypawn=(pieces_pawn)pawnsquare.pieces_chess;
						if (g.EnPassantPiece==enemypawn)
						{
							moves.Add(g.southeast(s));
						}
					}
                    pawnsquare=g.west(s);
                    if (pawnsquare!=null && pawnsquare.IsEnemyOf(Owner) && pawnsquare.pieces_chess is pieces_pawn)
					{
						pieces_pawn enemypawn=(pieces_pawn)pawnsquare.pieces_chess;
						if (g.EnPassantPiece==enemypawn)
						{
							moves.Add(g.southwest(s));
						}
					}
				}
			}
            return moves;
		}
    }
}
